<?php
date_default_timezone_set('PRC');

/* ================= 单文件工作记录系统 ================= */
ini_set('display_errors', 0);
error_reporting(0);
session_start();
const DB_FILE = __DIR__ . '/data.db';
const ADMIN_U = 'admin';
const ADMIN_P = '123456';   // 首次登录后请立刻修改
/* ---------------------------------------------------- */
/* 初始化数据库                                         */
/* ---------------------------------------------------- */
function initDb(): PDO
{
    static $pdo;
    if (isset($pdo)) return $pdo;
    $new = !file_exists(DB_FILE);
    $pdo = new PDO('sqlite:' . DB_FILE);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    if ($new) {
        $pdo->exec(<<<SQL
CREATE TABLE users(
    id   INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE NOT NULL,
    pass TEXT NOT NULL
);
CREATE TABLE records(
    id      INTEGER PRIMARY KEY AUTOINCREMENT,
    uid     INTEGER NOT NULL,
    title   TEXT NOT NULL,
    content TEXT NOT NULL,
    tags    TEXT,
    ctime   DATETIME NOT NULL
);
SQL
        );
        $stmt = $pdo->prepare("INSERT INTO users(name,pass) VALUES(?,?)");
        $stmt->execute([ADMIN_U, password_hash(ADMIN_P, PASSWORD_DEFAULT)]);
    }
    return $pdo;
}
/* ---------------------------------------------------- */
/* 工具函数                                             */
/* ---------------------------------------------------- */
function redirect(string $url = 'index.php'): void
{
    if (!headers_sent()) {
        header("Location: $url");
    } else {
        echo "<script>location.href='{$url}';</script>";
    }
    exit;
}
function getUser(): ?array { return $_SESSION['user'] ?? null; }
function requireLogin(): void { if (!getUser()) redirect('?act=login'); }
/* ---------------------------------------------------- */
/* 路由分发                                             */
/* ---------------------------------------------------- */
initDb();
$act = $_GET['act'] ?? 'home';
switch ($act) {
    case 'login':   handlerLogin();      break;
    case 'reg':     handlerReg();        break;
    case 'logout':  session_destroy(); redirect();
    case 'home':    handlerHome();       break;
    case 'add':     handlerAdd();        break;
    case 'edit':    handlerEdit();       break;
    case 'del':     handlerDel();        break;
    case 'search':  handlerSearch();     break;
    case 'export':  handlerExport();     break;
    case 'import':  handlerImport();     break;
    case 'chgpass': handlerChangePass(); break;
    /* admin 用户管理 */
    case 'um':      handlerUserManage(); break;
    case 'umexp':   handlerUserExport(); break;
    case 'umadd':   handlerUserAdd();    break;
    case 'umdel':   handlerUserDel();    break;
    case 'umreset': handlerUserReset();  break;
    default:        handlerHome();
}
/* ==================================================== */
/* 页面壳                                                */
/* ==================================================== */
function html(string $title, string $body): void
{ ?><!doctype html><html lang="zh-CN"><head>
<meta charset="utf-8"><title><?= $title ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif;background:#f7f7f7}
.header{background:#005ce6;color:#fff;padding:clamp(8px,2vw,16px) clamp(10px,3vw,20px);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap}
.header a{color:#fff;margin-left:12px;text-decoration:none}
.container{max-width:1300px;margin:20px auto;background:#fff;padding:clamp(10px,3vw,20px);border-radius:6px;box-shadow:0 0 4px rgba(0,0,0,.1)}
input[type=text],input[type=password],input[type=file],textarea{width:100%;padding:6px;font-size:clamp(14px,1.6vw,16px);box-sizing:border-box}
.btn{display:inline-block;background:#005ce6;color:#fff;padding:6px 12px;border:none;border-radius:4px;cursor:pointer;font-size:clamp(14px,1.6vw,16px)}
.tag{display:inline-block;background:#e0ebff;padding:2px 6px;margin:2px;border-radius:3px;font-size:clamp(12px,1.4vw,14px)}
table{width:100%;border-collapse:collapse;margin-top:10px;font-size:clamp(12px,1.4vw,15px)}
th,td{border:1px solid #ddd;padding:clamp(4px,1vw,8px) clamp(6px,1.5vw,10px);word-break:break-word}
th{background:#f2f2f2}
@media(max-width:600px){table{font-size:12px}th,td{padding:4px 6px}}
.ok-tip{color:green;font-weight:bold;margin-bottom:8px}
</style></head><body>
<div class="header"><div>工作记录系统</div><div class="nav"><?php if (getUser()) : ?>
  欢迎, <?= htmlspecialchars(getUser()['name']) ?> |
  <a href="?">首页</a> |
  <a href="?act=add">新增</a> |
  <a href="?act=search">搜索</a> |
  <a href="?act=export">导出XML</a> |
  <a href="?act=import">导入XML</a> |
  <a href="?act=chgpass">修改密码</a> |
  <?php if (getUser()['name'] === 'admin') : ?>
    <a href="?act=um">用户管理</a> |
  <?php endif; ?>
  <a href="?act=logout">退出</a>
<?php else : ?>
  <a href="?act=login">登录</a> | <a href="?act=reg">注册</a>
<?php endif ?></div></div>
<div class="container"><?= $body ?></div></body></html><?php }
/* ==================================================== */
/* 登录 / 注册                                           */
/* ==================================================== */
function handlerLogin(): void
{
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $name = trim($_POST['name'] ?? '');
        $pass = $_POST['pass'] ?? '';
        $pdo  = initDb();
        $st   = $pdo->prepare("SELECT * FROM users WHERE name=?");
        $st->execute([$name]);
        $u = $st->fetch(PDO::FETCH_ASSOC);
        if ($u && password_verify($pass, $u['pass'])) {
            $_SESSION['user'] = ['id' => $u['id'], 'name' => $u['name']];
            redirect();
        } else {
            $msg = '用户名或密码错误';
        }
    }
    $form = '<h3>登录</h3><form method="post"><p>用户名<br><input type="text" name="name" required></p><p>密码<br><input type="password" name="pass" required></p><p><button class="btn">登录</button></p></form><p>还没有账号？<a href="?act=reg">立即注册</a></p>';
    html('登录', $msg ?? '' . $form);
}
function handlerReg(): void
{
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $name = trim($_POST['name'] ?? '');
        $pass = $_POST['pass'] ?? '';
        if ($name === '' || $pass === '') {
            $msg = '用户名和密码不能为空';
        } else {
            $pdo = initDb();
            try {
                $hash = password_hash($pass, PASSWORD_DEFAULT);
                $pdo->prepare("INSERT INTO users(name,pass) VALUES(?,?)")->execute([$name, $hash]);
                $msg = '注册成功，<a href="?act=login">去登录</a>';
            } catch (PDOException $e) {
                $msg = '用户名已存在';
            }
        }
    }
    $form = '<h3>注册</h3><form method="post"><p>用户名<br><input type="text" name="name" required></p><p>密码<br><input type="password" name="pass" required></p><p><button class="btn">注册</button></p></form><p>已有账号？<a href="?act=login">立即登录</a></p>';
    html('注册', $msg ?? '' . $form);
}
/* ==================================================== */
/* 首页 / 增 / 改 / 删 / 搜                             */
/* ==================================================== */
function handlerHome(): void
{
    requireLogin();
    if (isset($_SESSION['ok'])) {
        $ok = $_SESSION['ok'];
        unset($_SESSION['ok']);
    } else {
        $ok = '';
    }

    $uid  = getUser()['id'];
    $pdo  = initDb();
    $rows = $pdo->query("SELECT * FROM records WHERE uid=$uid ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
    $tr   = '';
    foreach ($rows as $r) {
        $tagHtml = '';
        if ($r['tags']) {
            foreach (explode(',', $r['tags']) as $t) $tagHtml .= '<span class="tag">' . htmlspecialchars($t) . '</span>';
        }
        $tr .= "<tr><td>" . htmlspecialchars($r['title']) . "</td><td>" . mb_substr(strip_tags($r['content']), 0, 40) . "…</td><td>{$tagHtml}</td><td>{$r['ctime']}</td><td><a class='btn' href='?act=edit&id={$r['id']}'>改</a> <a class='btn' onclick=\"return confirm('删除?')\" href='?act=del&id={$r['id']}'>删</a></td></tr>";
    }
    $body = ($ok ? "<div class=\"ok-tip\">$ok</div>" : '') . '<h3>我的工作记录</h3><table><tr><th>标题</th><th>内容摘要</th><th>标签</th><th>时间</th><th>操作</th></tr>' . ($tr ?: '<tr><td colspan="5">暂无记录</td></tr>') . '</table>';
    html('首页', $body);
}
function handlerAdd(): void  { handlerAddEdit(false); }
function handlerEdit(): void { handlerAddEdit(true); }
function handlerAddEdit(bool $isEdit): void
{
    requireLogin();
    $uid  = getUser()['id'];
    $pdo  = initDb();
    $id   = (int)($_GET['id'] ?? 0);
    if ($isEdit) {
        $st = $pdo->prepare("SELECT * FROM records WHERE id=? AND uid=?");
        $st->execute([$id, $uid]);
        $old = $st->fetch(PDO::FETCH_ASSOC);
        if (!$old) { html('错误', '无此记录'); exit; }
    } else {
        $old = ['title' => '', 'content' => '', 'tags' => ''];
    }
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $title   = trim($_POST['title'] ?? '');
        $content = trim($_POST['content'] ?? '');
        $tags    = trim($_POST['tags'] ?? '');
        if ($title === '' || $content === '') {
            $msg = '标题和内容必填';
        } else {
            $now = date('Y-m-d H:i:s');
            if ($isEdit) {
                $st = $pdo->prepare("UPDATE records SET title=?,content=?,tags=?,ctime=? WHERE id=? AND uid=?");
                $st->execute([$title, $content, $tags, $now, $id, $uid]);
            } else {
                $st = $pdo->prepare("INSERT INTO records(uid,title,content,tags,ctime) VALUES(?,?,?,?,?)");
                $st->execute([$uid, $title, $content, $tags, $now]);
            }
            redirect();
        }
    }
    $body = ($msg ?? '') . '<h3>' . ($isEdit ? '编辑' : '新增') . '记录</h3><form method="post"><p>标题<br><input type="text" name="title" value="' . htmlspecialchars($old['title']) . '" required></p><p>内容<br><textarea name="content" rows="8" required>' . htmlspecialchars($old['content']) . '</textarea></p><p>标签（用逗号分隔）<br><input type="text" name="tags" value="' . htmlspecialchars($old['tags']) . '"></p><p><button class="btn">保存</button></p></form>';
    html($isEdit ? '编辑' : '新增', $body);
}
function handlerDel(): void
{
    requireLogin();
    $uid = getUser()['id'];
    $id  = (int)($_GET['id'] ?? 0);
    $pdo = initDb();
    $pdo->prepare("DELETE FROM records WHERE id=? AND uid=?")->execute([$id, $uid]);
    redirect();
}
function handlerSearch(): void
{
    requireLogin();
    $uid = getUser()['id'];
    $q   = trim($_GET['q'] ?? '');
    $body = '<h3>模糊搜索</h3><form method="get"><input type="hidden" name="act" value="search"><input type="text" name="q" value="' . htmlspecialchars($q) . '" placeholder="关键词"><button class="btn">搜索</button></form>';
    if ($q !== '') {
        $pdo  = initDb();
        $st   = $pdo->prepare("SELECT * FROM records WHERE uid=? AND (title LIKE '%'||?||'%' OR content LIKE '%'||?||'%' OR tags LIKE '%'||?||'%' OR ctime LIKE '%'||?||'%') ORDER BY id DESC");
        $st->execute([$uid, $q, $q, $q, $q]);
        $rows = $st->fetchAll(PDO::FETCH_ASSOC);
        $tr   = '';
        foreach ($rows as $r) {
            $tagHtml = '';
            if ($r['tags']) {
                foreach (explode(',', $r['tags']) as $t) $tagHtml .= '<span class="tag">' . htmlspecialchars($t) . '</span>';
            }
            $tr .= "<tr><td>" . htmlspecialchars($r['title']) . "</td><td>" . mb_substr(strip_tags($r['content']), 0, 40) . "…</td><td>{$tagHtml}</td><td>{$r['ctime']}</td><td><a class='btn' href='?act=edit&id={$r['id']}'>改</a></td></tr>";
        }
        $body .= '<table><tr><th>标题</th><th>内容摘要</th><th>标签</th><th>时间</th><th>操作</th></tr>' . ($tr ?: '<tr><td colspan="5">无结果</td></tr>') . '</table>';
    }
    html('搜索', $body);
}
/* ---------------------------------------------------- */
/* 导出 / 导入 Excel 2007 XML                          */
/* ---------------------------------------------------- */
function handlerExport(): void
{
    requireLogin();
    $uid  = getUser()['id'];
    $pdo  = initDb();
    $rows = $pdo->query("SELECT * FROM records WHERE uid=$uid ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
    $xml  = '<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<Styles><Style ss:ID="s1"><Font ss:Bold="1"/></Style></Styles>
<Worksheet ss:Name="记录"><Table>';
    $xml .= '<Row>' . implode('', array_map(fn($h) => "<Cell><Data ss:Type=\"String\">$h</Data></Cell>", ['ID', '标题', '内容', '标签', '创建时间'])) . '</Row>';
    foreach ($rows as $r) {
        $cells = [$r['id'], $r['title'], $r['content'], $r['tags'], $r['ctime']];
        $xml  .= '<Row>' . implode('', array_map(fn($v) => "<Cell><Data ss:Type=\"String\">" . htmlspecialchars($v) . "</Data></Cell>", $cells)) . '</Row>';
    }
    $xml .= '</Table></Worksheet></Workbook>';
    header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="records_' . date('Ymd_His') . '.xml"');
    header('Content-Length: ' . strlen($xml));
    echo $xml;
    exit;
}
function handlerImport(): void
{
    requireLogin();
    $uid  = getUser()['id'];
    $msg  = '';
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['xls'])) {
        $file = $_FILES['xls']['tmp_name'];
        if (!is_uploaded_file($file)) {
            $msg = '上传失败';
        } else {
            $content = file_get_contents($file);
            $xml     = @simplexml_load_string($content);
            if (!$xml) {
                $msg = '无法解析文件，请使用本系统导出的XML';
            } else {
                $pdo = initDb();
                $st  = $pdo->prepare("INSERT INTO records(uid,title,content,tags,ctime) VALUES(?,?,?,?,?)");
                $cnt = 0;
                foreach ($xml->Worksheet->Table->Row as $idx => $row) {
                    if ($idx == 0) continue;
                    $cells = $row->Cell;
                    $title = (string)$cells[1]->Data;
                    $cont  = (string)$cells[2]->Data;
                    $tags  = (string)$cells[3]->Data;
                    $ctime = (string)$cells[4]->Data;
                    if ($title === '') continue;
                    $ck = $pdo->prepare("SELECT id FROM records WHERE uid=? AND title=? AND ctime=?");
                    $ck->execute([$uid, $title, $ctime]);
                    if ($ck->fetch()) continue;
                    $st->execute([$uid, $title, $cont, $tags, $ctime]);
                    $cnt++;
                }
                $msg = "成功导入 {$cnt} 条记录";
            }
        }
    }
    $body = ($msg ? "<p>{$msg}</p>" : '') . '<h3>导入 Excel</h3><p>仅支持由本系统导出的 <b>.xml</b> 文件（Excel2007 格式）</p><form method="post" enctype="multipart/form-data"><input type="file" name="xls" accept=".xml" required><button class="btn">上传导入</button></form>';
    html('导入', $body);
}
/* ==================================================== */
/* 用户自行修改密码（含成功提示+跳转）                   */
/* ==================================================== */
function handlerChangePass(): void
{
    requireLogin();
    $uid  = getUser()['id'];
    $pdo  = initDb();
    $msg  = '';

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $oldPass  = $_POST['oldpass']  ?? '';
        $newPass  = $_POST['newpass']  ?? '';
        $newPass2 = $_POST['newpass2'] ?? '';

        if ($oldPass === '' || $newPass === '' || $newPass2 === '') {
            $msg = '请完整填写三项内容';
        } elseif ($newPass !== $newPass2) {
            $msg = '两次新密码不一致';
        } elseif (strlen($newPass) < 6) {
            $msg = '新密码至少 6 位';
        } else {
            $st = $pdo->prepare("SELECT pass FROM users WHERE id=?");
            $st->execute([$uid]);
            $hash = $st->fetchColumn();
            if (!password_verify($oldPass, $hash)) {
                $msg = '旧密码错误';
            } else {
                $newHash = password_hash($newPass, PASSWORD_DEFAULT);
                $pdo->prepare("UPDATE users SET pass=? WHERE id=?")->execute([$newHash, $uid]);
                $_SESSION['ok'] = '密码修改成功！';
                redirect();
            }
        }
    }

    $form = <<<HTML
<h3>修改密码</h3>
<form method="post">
  <p>旧密码<br><input type="password" name="oldpass" required></p>
  <p>新密码<br><input type="password" name="newpass" required minlength="6"></p>
  <p>确认新密码<br><input type="password" name="newpass2" required minlength="6"></p>
  <p><button class="btn">保存</button></p>
</form>
HTML;
    html('修改密码', ($msg ? "<p>{$msg}</p>" : '') . $form);
}
/* ==================================================== */
/* Admin 用户管理                                        */
/* ==================================================== */
function handlerUserManage(): void
{
    requireLogin();
    if (getUser()['name'] !== 'admin') { html('无权', '无权访问'); exit; }
    $pdo  = initDb();
    $rows = $pdo->query("SELECT id,name FROM users ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
    $tr   = '';
    foreach ($rows as $u) {
        $tr .= "<tr><td>{$u['id']}</td><td>" . htmlspecialchars($u['name']) . "</td><td>
          <a class='btn' onclick=\"return confirm('重置密码为 123456？')\" href='?act=umreset&uid={$u['id']}'>重置密码</a>
          <a class='btn' href='?act=umexp&uid={$u['id']}'>导出数据</a>
          <a class='btn' onclick=\"return confirm('删除该用户？')\" href='?act=umdel&uid={$u['id']}'>删除</a>
        </td></tr>";
    }
    $body = '<h3>用户管理</h3><p><a class="btn" href="?act=umadd">新增用户</a></p><table><tr><th>ID</th><th>用户名</th><th>操作</th></tr>' . $tr . '</table>';
    html('用户管理', $body);
}
function handlerUserAdd(): void
{
    requireLogin();
    if (getUser()['name'] !== 'admin') redirect();
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $name = trim($_POST['name'] ?? '');
        $pass = $_POST['pass'] ?? '';
        if ($name === '' || $pass === '') {
            $msg = '用户名和密码不能为空';
        } else {
            $pdo = initDb();
            try {
                $hash = password_hash($pass, PASSWORD_DEFAULT);
                $pdo->prepare("INSERT INTO users(name,pass) VALUES(?,?)")->execute([$name, $hash]);
                redirect('?act=um');
            } catch (PDOException $e) {
                $msg = '用户名已存在';
            }
        }
    }
    $body = ($msg ?? '') . '<h3>新增用户</h3><form method="post"><p>用户名<br><input type="text" name="name" required></p><p>密码<br><input type="password" name="pass" required></p><p><button class="btn">创建</button></p></form>';
    html('新增用户', $body);
}
function handlerUserDel(): void
{
    requireLogin();
    if (getUser()['name'] !== 'admin') redirect();
    $uid = (int)($_GET['uid'] ?? 0);
    if ($uid === 1) redirect('?act=um');
    $pdo = initDb();
    $pdo->prepare("DELETE FROM users WHERE id=?")->execute([$uid]);
    redirect('?act=um');
}
function handlerUserReset(): void
{
    requireLogin();
    if (getUser()['name'] !== 'admin') redirect();
    $uid  = (int)($_GET['uid'] ?? 0);
    $pdo  = initDb();
    $hash = password_hash('123456', PASSWORD_DEFAULT);
    $pdo->prepare("UPDATE users SET pass=? WHERE id=?")->execute([$hash, $uid]);
    redirect('?act=um');
}
/* ==================================================== */
/* 管理员导出指定用户数据（PHP≥5.6 无箭头函数）          */
/* ==================================================== */
function handlerUserExport()
{
    requireLogin();
    if (getUser()['name'] !== 'admin') {
        redirect();
    }

    $targetUid = isset($_GET['uid']) ? (int)$_GET['uid'] : 0;
    if (!$targetUid) {
        redirect('?act=um');
    }

    $pdo  = initDb();
    $stmt = $pdo->prepare("SELECT * FROM records WHERE uid=? ORDER BY id DESC");
    $stmt->execute([$targetUid]);
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if (!$rows) {
        $_SESSION['ok'] = '该用户无数据可导出';
        redirect('?act=um');
    }

    /* 拼 Excel 2007 XML – 不用任何箭头函数 */
    $xml  = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    $xml .= '<?mso-application progid="Excel.Sheet"?>' . "\n";
    $xml .= '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet">';
    $xml .= '<Styles><Style ss:ID="s1"><Font ss:Bold="1"/></Style></Styles>';
    $xml .= '<Worksheet ss:Name="记录"><Table>';

    // 表头
    $xml .= '<Row>';
    foreach (['ID', '标题', '内容', '标签', '创建时间'] as $h) {
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($h) . '</Data></Cell>';
    }
    $xml .= '</Row>';

    // 数据行
    foreach ($rows as $r) {
        $xml .= '<Row>';
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($r['id'])     . '</Data></Cell>';
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($r['title'])  . '</Data></Cell>';
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($r['content']). '</Data></Cell>';
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($r['tags'])   . '</Data></Cell>';
        $xml .= '<Cell><Data ss:Type="String">' . htmlspecialchars($r['ctime'])  . '</Data></Cell>';
        $xml .= '</Row>';
    }

    $xml .= '</Table></Worksheet></Workbook>';

    // 文件名
    $nameRow = $pdo->prepare("SELECT name FROM users WHERE id=?");
    $nameRow->execute([$targetUid]);
    $userName = $nameRow->fetchColumn();
    $fileName = $userName . '_records_' . date('Ymd_His') . '.xml';

    header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="' . $fileName . '"');
    header('Content-Length: ' . strlen($xml));
    echo $xml;
    exit;
}
